#include "common.h"
#include "datastruct.h"
#include <assert.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define BUFSIZE 2048
#define NAMESIZE 2048

/*ss所需初值*/
/*************************************************************************************/	
/*打印级别列表*/
#define EXIT -1   //强制让某个客户端下线
#define INFO 1    //打印服务器端口
#define DEBUG 2   //打印客户发送内容
#define WARNING 3 //警告信息
#define ERR 4     //错误信息
#define GETUSER 6 //获取用户信息
#define GETSTAT 9 //获取服务器状态信息

#define BUFFSIZE 20

/*全局变量，用于设置打印级别*/
int global = 3;

/*表驱动结构体*/
typedef struct _levelHandler{
    int t_level;
    void (*pfun)(int, void *);
} Level_handler;

/*INFO打印级别，用于打印服务器端口、IP*/
void finfo(int temp_global, void* input);
/*DEBUG打印级别，用于打印其中一个在线客户端发送的消息内容*/
void fdebug(int temp_global, void* input);
/*WARNING打印级别，用于打印警告信息*/
void fwarning(int temp_global, void* input);
/*ERR打印级别，用于打印错误信息，并且退出*/
void ferr(int temp_global, void* input);
/*获取在线所有用户的用户名*/
void fgetuser(int temp_global, void* input);
/*强制让某个客户端下线*/
void fexit(int temp_global, void* input);
/*获取服务器的状态信息*/
void fgetstat(int temp_global, void* input);

/*表驱动结构体数组列表*/
Level_handler print_lev[] = {
        {-1, fexit},
		{1, finfo},
		{2, fdebug},
		{3, fwarning},
		{4, ferr},
		{6, fgetuser},
		{9, fgetstat}
	};

/*ss调试线程*/
void *ss_debug(void *arg)
{
    int *t_shm = (int *)arg;
    while(1)
    {
        sleep(1);
        global = *t_shm;
        //printf("thread global : %d\n", global);
    } 
    return NULL;
}
/*************************************************************************************/	


typedef struct name
{
    char *name_buf[100];
}Name;

//int list_for_each(Link_head *head, fd_set *set);
int list_for_each(Link_head *head, fd_set *set, int *maxsock);
int list_each_fd(Link_head *head, fd_set *set);
User *node_create(char name[], int fd);
void node_insert_tail(Link_head *linklist, User *pNode);
User *node_search(Link_head *linklist, char name[]);
User *list_delete(User *next, Link_head *head);

int main()
{
	
	
/*共享内存创建*/
/*************************************************************************************/
	key_t key;
    int shmid;
    int *shmaddr = NULL;

    printf("before global : %d\n", global);

    key = ftok("./", 802);
    if(key < 0)
    {
        err_sys("ftok error");
    }

    shmid = shmget(key, BUFFSIZE, IPC_CREAT | 0666);
    if(shmid == -1)
    {
        err_sys("shmget error");
    }

    shmaddr = shmat(shmid, NULL, 0);
    printf("shmaddr addr : %p\n", shmaddr);
    if(shmaddr < 0)
    {
        err_sys("shmat error");
    }
    printf("shmaddr data :%d\n",*shmaddr);
/*************************************************************************************/	


/*SS调试线程创建*/
/*************************************************************************************/	
	pthread_t tid;
    pthread_create(&tid, NULL, ss_debug, (void *)shmaddr);
    pthread_detach(tid);

    //sleep(1);//等待线程响应
/*************************************************************************************/		
	
	
	
    Link_head head;
    head.head = NULL;
    int sockfd;
    struct timeval tv = {8, 0};
    
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
        err_sys("socket error");

    int sockopt = 1;
    if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt))) < 0)
        err_sys("setsockopt error");

    struct sockaddr_in my_addr;
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(9999);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);


    int ret;
    ret = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
    if(ret != 0)
        err_sys("bind error");

    ret = listen(sockfd, 10);
    if(ret != 0)
        err_sys("listen error");

    printf("Listen...\n");
    int maxsock = sockfd;

//    fd_set rset;
//    FD_ZERO(&rset);
//    FD_SET(sockfd, &rset);

    while(1)
    {
        fd_set rset;
        FD_ZERO(&rset);
        FD_SET(sockfd, &rset);
        list_for_each(&head, &rset, &maxsock);

        ret = select(maxsock + 1, &rset, NULL, NULL, &tv);
        if(ret == -1)
            err_sys("select error");
        else if(ret == 0)
            continue;

        char client_ip[INET_ADDRSTRLEN] = {0};
        struct sockaddr_in client_addr;
        socklen_t cliaddr_len = sizeof(client_addr);

        list_each_fd(&head, &rset);

        if(FD_ISSET(sockfd, &rset))
		{
            printf("accept\n");
            int connfd;
            char send_buf[20] = "";
			Message use_buf; 
			connfd = accept(sockfd,  (struct sockaddr*)&client_addr, &cliaddr_len);
			if(connfd < 0)
				err_sys("accept error");
	
            struct timeval srtv = {40, 0};
            setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, &srtv, sizeof(srtv));
            setsockopt(connfd, SOL_SOCKET, SO_SNDTIMEO, &srtv, sizeof(srtv));

            inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
            printf("client ip=%s, port=%d\n", client_ip, ntohs(client_addr.sin_port));

            while(1)
            {
            bzero(&use_buf, sizeof(use_buf));
            ret = recv(connfd, &use_buf, sizeof(use_buf), 0);
			if(ret == -1)
			    err_sys("recv error");
            
			if(use_buf.type == REGISTER)
			{
				User *pos = node_search(&head, use_buf.fromuser);
                if(pos == NULL)
				{
                    strcpy(send_buf, "Success");
					User *pnode = node_create(use_buf.fromuser, connfd);
					node_insert_tail(&head, pnode);
//                    assert(pnode);
                    if(connfd > maxsock)
                        maxsock = connfd;

	    			send(connfd, send_buf, strlen(send_buf), 0);
                    User *next = head.head;
                    while(next != NULL)
                    {
                        printf("head.head.time:%ld, %d, %s", next->time, next->fd, next->user_name);
                        next = next->next;
                    }
                    printf("%d\n", maxsock);
                    break;
				}
                else
				{
                    strcpy(send_buf, "Error");
					send(connfd, send_buf, strlen(send_buf), 0);
                    continue;
                }
			}
			bzero(send_buf, sizeof(send_buf));
            }
		}
    }

	
/*共享内存删除*/	
/*************************************************************************************/	
	int shm_ret = shmdt(shmaddr);
	if(shm_ret == -1)
	{
		err_sys("shmdt error");
	}
	shm_ret = shmctl(shmid, IPC_RMID, NULL);
	if(shm_ret == -1)
	{
		err_sys("shmctl error");
	}
/*************************************************************************************/	
    return 0;
}

User *list_delete(User *next, Link_head *head)
{
    Link_head *linklist = head;
    User *p = head->head;

    if(next == linklist->head)
    {
        linklist->head = next->next;
        free(next);
        next = NULL;
        return head->head;
    }
    
    while(p->next != next && p->next != NULL)
    {
        p = p->next;
    }
    p->next = next->next;
    free(next);
    next = NULL;
    return p->next;
}

User *node_create(char name[], int fd)
{
	User *pnode = (User*)malloc(sizeof(User));
	assert(pnode);
	strncpy(pnode->user_name, name, strlen(name));
	pnode->fd = fd;
	pnode->time = time(NULL);
	pnode->next = NULL;

	return pnode;
}

void node_insert_tail(Link_head *linklist, User *pNode)
{
	if(linklist->head == NULL)
		linklist->head = pNode;
	else
	{
		User *p = linklist->head;
		while(p->next != NULL)
			p = p->next;

		p->next = pNode;
	}
}

User *node_search(Link_head *linklist, char name[])
{
	User *p = linklist->head;
	while(p != NULL)
	{
		if(strcmp(p->user_name, name) == 0)
		{
			return p;
		}
	    p = p->next;
	}
	return NULL;
}


int list_for_each(Link_head *head, fd_set *set, int *maxsock)
{
    User *next = head->head;
    while(next != NULL)
    {
        if((time(NULL) - next->time) > 60)
        {
            close(next->fd);
            FD_CLR(next->fd, set);
            next = list_delete(next, head);
//            continue;
        }
        else
        {
            FD_SET(next->fd, set);
            next = next->next;
   /*         if((*maxsock) < next->fd)
            {
                *maxsock = next->fd;
            }
            */
        }
    }

    return 0;
}

int list_each_fd(Link_head *head, fd_set *set)
{
    int flag = 0;
    User *next = head->head;
    User *p = head->head;
    Message message;
    while(next != NULL)
    {
        printf("!!!!!!!\n");
        if(FD_ISSET(next->fd, set))
        {
            int ret = recv(next->fd, &message, sizeof(message), 0);
            printf("**********\n");
			printf("message:%d\n", message.type);

            if(ret == -1)
                err_sys("receive error");
            else if(ret == 0)
            {
                if(next == head->head)
                {
                    close(next->fd);
                    FD_CLR(next->fd, set);
                    head->head = next->next;
                    free(next);
                    next = head->head;
                }
                else
                {
                    close(next->fd);
                    p->next = next->next;
                    free(next);
                    next = NULL;
                }
            }
            else 
            {
                if(message.type == GETUSER)
                {
                    User *n = head->head;
                    char name[1024] = {0};
					sprintf(name,"user:%s\n", "");
                    while(n != NULL)
                    {
						strcat(name, n->user_name);
						n = n->next;
                    }
					
					//****************************************************
					//printf("%s\n",name);
					print_lev[5].pfun(global, (void *)head->head);
					//****************************************************
					
                    send(next->fd, name, sizeof(name), 0);
                }
                if(message.type == KEEPLIVE)
                {
                    next->time = message.time;
                }
                if(message.type == DATA)
                {
                    User *n = node_search(head, message.touser);
                    if(n != NULL)
                    {
						flag = 1;
						send(n->fd, &message, sizeof(message), 0);
                    }
                    if(flag == 0)
                    {
						
						//****************************************************
						print_lev[3].pfun(global, "The user does not exist !\n");
						//****************************************************
						
						bzero(&message, sizeof(message));
						message.type = DATA;
						strcpy(message.fromuser, "server");
                        strcpy(message.data, "The user does not exist!\n");
                        send(next->fd, &message, sizeof(message), 0);
                    }
                }
            }
			bzero(&message, sizeof(message));
            break;
        }
        if(next == head->head)
        {
            next = next->next;
        }
        else
        {
            p = p->next;
            next = p->next;
        }
    }

    return 0;
}

/*INFO打印级别，用于打印服务器端口、IP*/
void finfo(int temp_global, void* input)
{
    if(INFO == temp_global)
    {
        printf("\n|******Current print level number : %d. ******|\n", temp_global);
        struct sockaddr_in *temp_addr = (struct sockaddr_in *)input;
        char current_ip[INET_ADDRSTRLEN] = {0};
        inet_ntop(AF_INET, &temp_addr->sin_addr, current_ip, INET_ADDRSTRLEN);
        printf("Server IP : %s\n", current_ip);
        printf("Server Port : %d\n", ntohs(temp_addr->sin_port));
    }	
}
/*DEBUG打印级别，用于打印其中一个在线客户端发送的消息内容*/
void fdebug(int temp_global, void* input)
{
    if(DEBUG == temp_global)
    {
        printf("\n|******Current print level number : %d. ******|\n", temp_global);
        char *temp_buf = (char *)input;
        printf("Recv data : %s\n", temp_buf);
    }
}
/*WARNING打印级别，用于打印警告信息*/
void fwarning(int temp_global, void* input)
{
    if(WARNING == temp_global)
    {
        printf("\n|******Current print level number : %d. ******|\n", temp_global);
        char *temp_buf = (char *)input;
        printf("WARNING : %s\n", temp_buf);
    }
}
/*ERR打印级别，用于打印错误信息，并且退出*/
void ferr(int temp_global, void* input)
{
    if(ERR == temp_global)
    {
        printf("\n|******Current print level number : %d. ******|\n", temp_global);
        char *temp_buf = (char *)input;
        printf("Error : %s\n", temp_buf);
        exit(0);
    }
}
/*获取在线所有用户的用户名*/
void fgetuser(int temp_global, void* input)
{
	if(GETUSER == temp_global)
	{
		printf("\n|******Current print level number : %d. ******|\n", temp_global);
		
		User *n = (Uesr *)input;
		char name[1024] = {0};
		sprintf(name,"user:%s\n", "");
		while(n != NULL)
		{
			strcat(name, n->user_name);
			n = n->next;
		}
		printf("\n|**********User List**********|\n")
		printf("%s\n",name);
	}
}
/*强制让某个客户端下线*/
void fexit(int temp_global, void* input)
{
    if(EXIT == temp_global)
    {
        //sleep(1);
        printf("\n|******Current print level number : %d. ******|\n", temp_global);
        int *temp_buf = (int *)input;
        printf("Close Client : %d\n", *temp_buf);
        close(*temp_buf);
        printf("Client has closed !\n");
    }
}
/*获取服务器的状态信息*/
void fgetstat(int temp_global, void* input)
{
	if(GETSTAT == temp_global)
	{
		printf("\n|******Current print level number : %d. ******|\n", temp_global);	
		char str[32];
		struct hostent *host;
		host = gethostbyname("localhost");
		printf("\nAddress : %s\n", inet_ntop(host->h_addrtype, *(host->h_addr_list), str, 32));
	}
}